/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.spi.entity.builtinimpls;

import com.inspur.edp.bef.spi.entity.CodeRuleInfo;
import com.inspur.edp.bef.spi.entity.columnconfig.ColumnGenerateInfo;
import com.inspur.edp.cef.api.repository.GspDbDataType;
import com.inspur.edp.cef.entity.entity.FieldType;
import com.inspur.edp.cef.spi.entity.PropertyDefaultValue;
import com.inspur.edp.cef.spi.entity.info.EnumValueInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.AssocationPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.BasePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.ComplexUdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.EnumPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.ObjectType;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.SimpleAssoUdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.SimpleEnumUdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.SimpleUdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefEntityResInfoImpl;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefModelResInfoImpl;

import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefValueObjModelResInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefValueObjResInfo;
import com.inspur.edp.udt.api.Manager.IUdtManager;
import com.inspur.edp.udt.api.UdtManagerUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public abstract class BefEntityResInfoImpl extends CefEntityResInfoImpl {

    private HashMap<String, CodeRuleInfo> beforeSaveCodeRules;
    private HashMap<String,CodeRuleInfo> afterCreateCodeRules;
    private String versionControlPropertyName;

    public BefEntityResInfoImpl(String entityCode, String displayValueKey, CefModelResInfoImpl modelResInfo, String entityId) {
        super(entityCode, displayValueKey, modelResInfo, entityId);
    }

    public HashMap<String, CodeRuleInfo> getAfterCreateCodeRules() {
        if(afterCreateCodeRules == null)
            afterCreateCodeRules = new HashMap<>();
        return afterCreateCodeRules;
    }

    public HashMap<String, CodeRuleInfo> getBeforeSaveCodeRules() {
        if(beforeSaveCodeRules == null)
            beforeSaveCodeRules = new HashMap<>();
        return beforeSaveCodeRules;
    }

    public String getVersionControlPropertyName() {
        return versionControlPropertyName;
    }

    public void setVersionControlPropertyName(String versionControlPropertyName) {
        this.versionControlPropertyName = versionControlPropertyName;
    }

  protected DataTypePropertyInfo addPropertyInfo(String propertyName, String displayValueKey,
      boolean required, boolean enableRtrim, int length, int pricision,
      FieldType fieldType, ObjectType objectType, PropertyDefaultValue defaultValue,
      boolean defaultNull, boolean isMulti, GspDbDataType dbDataType, String dbColumnName,
      BasePropertyInfo basePropertyInfo) {
    DataTypePropertyInfo dataTypePropertyInfo = createDataTypePropertyInfo(propertyName,
        displayValueKey, required, enableRtrim, length, pricision,
        fieldType, objectType, defaultValue, isMulti, defaultNull, dbDataType, dbColumnName,
        basePropertyInfo);
    addPropertyInfo(dataTypePropertyInfo);
    return dataTypePropertyInfo;
  }

  protected DataTypePropertyInfo addStringPropertyInfo(String propertyName, boolean required,
      boolean enableRtrim, int length) {
    return addStringPropertyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        required, enableRtrim, length, null, false, false, GspDbDataType.VarChar, propertyName);
  }

  protected DataTypePropertyInfo addStringPropertyInfo(String propertyName,
      String displayValueKey, boolean required, boolean enableRtrim, int length,
      PropertyDefaultValue defaultValue, boolean defaultNull, boolean isMulti,
      GspDbDataType dbDataType, String dbColumnName) {
    return addPropertyInfo(propertyName, displayValueKey, required, enableRtrim, length, 0,
        FieldType.String, ObjectType.Normal, defaultValue, defaultNull, isMulti, dbDataType,
        dbColumnName, null);
  }

  protected DataTypePropertyInfo addTextPropertyInfo(String propertyName, boolean required,
      boolean enableRtrim) {
    return addTextPropertyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        required,
        enableRtrim, null, false, false, GspDbDataType.Clob, propertyName);
  }

  protected DataTypePropertyInfo addTextPropertyInfo(String propertyNme, String displayValueKey,
      boolean requried, boolean enableRtrim, PropertyDefaultValue defaultValue,
      boolean isDefaultNull,
      boolean isMulti, GspDbDataType dbDataType, String dbColumnName) {
    return addPropertyInfo(propertyNme, displayValueKey, requried, enableRtrim, 0, 0,
        FieldType.Text, ObjectType.Normal, defaultValue, isDefaultNull, isMulti, dbDataType,
        dbColumnName, null);
  }


  protected DataTypePropertyInfo addDatePropertyInfo(String propertyName, boolean required) {
    return addDatePropertyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        required, null, false, GspDbDataType.DateTime, propertyName);
  }

  protected DataTypePropertyInfo addDatePropertyInfo(String propertyName, String displayValueKey,
      boolean required, PropertyDefaultValue defaultValue
      , boolean defaultNull, GspDbDataType dbDataType, String dbColumnName) {
    return addPropertyInfo(propertyName, displayValueKey, required, false, 0, 0, FieldType.Date,
        ObjectType.Normal, defaultValue, defaultNull, false, dbDataType, dbColumnName, null);
  }

  protected DataTypePropertyInfo addDateTimePropertyInfo(String propertyName, boolean required) {
    return addDateTimePropertyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        required, null, false, GspDbDataType.DateTime, propertyName);
  }

  protected DataTypePropertyInfo addDateTimePropertyInfo(String propertyName,
      String displayValueKey, boolean required, PropertyDefaultValue defaultValue,
      boolean defaultNull, GspDbDataType dbDataType, String dbColumnName) {
    return addPropertyInfo(propertyName, displayValueKey, required, false, 0, 0,
        FieldType.DateTime, ObjectType.Normal, defaultValue, defaultNull, false, dbDataType,
        dbColumnName, null);
  }

  protected DataTypePropertyInfo addIntPropertyInfo(String propertyName, boolean required) {
    return addIntPropertyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        required, null, false, GspDbDataType.Int, propertyName);
  }

  protected DataTypePropertyInfo addIntPropertyInfo(String propertyName, String displayValueKey,
      boolean required, PropertyDefaultValue defaultValue,
      boolean defaultNull, GspDbDataType dbDataType, String dbColumnName) {
    return addPropertyInfo(propertyName, displayValueKey, required, false, 0, 0,
        FieldType.Integer, ObjectType.Normal, defaultValue, defaultNull, false, dbDataType,
        dbColumnName, null);
  }

  protected DataTypePropertyInfo addDecimalPropertyInfo(String propertyName, boolean requried,
      int length, int pricision) {
    return addDecimalPropertyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        requried, length, pricision, null, false, GspDbDataType.Decimal, propertyName);
  }

  protected DataTypePropertyInfo addDecimalPropertyInfo(String propertyName,
      String propertyDispalyKey, boolean requried, int length, int pricision,
      PropertyDefaultValue defaultValue, boolean defaultNull, GspDbDataType dbDataType,
      String dbColumnName) {
    return addPropertyInfo(propertyName, propertyDispalyKey, requried, false, length, pricision,
        FieldType.Decimal, ObjectType.Normal, defaultValue, defaultNull, false, dbDataType,
        dbColumnName, null);
  }

  protected DataTypePropertyInfo addBooleanPropertyInfo(String propertyName, boolean requried) {
    return addBooleanPropertyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        requried, null, false, GspDbDataType.Char, propertyName);
  }

  protected DataTypePropertyInfo addBooleanPropertyInfo(String propertyName,
      String propertyDisplayValue, boolean required, PropertyDefaultValue defaultValue,
      boolean defaultNull, GspDbDataType dbDataType, String dbColumnName) {
    return addPropertyInfo(propertyName, propertyDisplayValue, required, false, 0, 0,
        FieldType.Boolean, ObjectType.Normal, defaultValue, defaultNull, false, dbDataType,
        dbColumnName, null);
  }

  protected String getFieldPropertyDisplayValue(String propertyName) {
    return getDisplayPrefix() + "." + propertyName + ".Name";
  }

  protected DataTypePropertyInfo addBytesPropertyInfo(String propertyName, boolean required) {
    return addBytesPropertyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        required, null, false, GspDbDataType.Blob, propertyName);
  }

  protected DataTypePropertyInfo addBytesPropertyInfo(String propertyName, String displayValueKey,
      boolean required, PropertyDefaultValue defaultValue,
      boolean defaultNull, GspDbDataType dbDataType, String dbColumnName) {
    return addPropertyInfo(propertyName, displayValueKey, required, false, 0, 0,
        FieldType.Binary, ObjectType.Normal, defaultValue, defaultNull, false, dbDataType,
        dbColumnName, null);
  }

  protected final DataTypePropertyInfo addAssociationProperyInfo(String propertyName, boolean required,
      boolean enableRtrim,
      AssocationPropertyInfo associationInfo) {
    return addAssociationProperyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        required, enableRtrim, 36, false, associationInfo, GspDbDataType.VarChar,
        propertyName);
  }

  protected final DataTypePropertyInfo addAssociationProperyInfo(String propertyName,
      String propertyDisplayKey, boolean required, boolean enableRtrim, int length,
      boolean isDefaultNull, AssocationPropertyInfo associationInfo,
      GspDbDataType dbDataType, String dbColumnName) {
    return addPropertyInfo(propertyName, propertyDisplayKey, required, enableRtrim, length, 0,
        FieldType.String, ObjectType.Association, null, isDefaultNull, false, dbDataType,
        dbColumnName, associationInfo);
  }

//  protected final DataTypePropertyInfo addEnumPropertyInfo(String propertyName,boolean required,EnumPropertyInfo enumPropertyInfo)
//  {
//    return addEnumPropertyInfo(propertyName,getFieldPropertyDisplayValue(propertyName),required,enumPropertyInfo,GspDbDataType.VarChar,propertyName);
//  }
//
//  protected  final DataTypePropertyInfo addEnumPropertyInfo(String propertyName,String propertyDisplayKey,boolean required,EnumPropertyInfo enumPropertyInfo,GspDbDataType dbDataType,String dbColumnName)
//  {
//    return addPropertyInfo(propertyName, propertyDisplayKey, required, false, 0, 0,
//        FieldType.String, ObjectType.Enum, null, false, false, dbDataType,
//        dbColumnName, enumPropertyInfo);
//  }

  protected final DataTypePropertyInfo addAssoUdtPropertyInfo(String propertyName, boolean requried,
      boolean enableRtrim,  SimpleAssoUdtPropertyInfo associationInfo,GspDbDataType dbDataType) {
    return addAssoUdtPropertyInfo(propertyName, getFieldPropertyDisplayValue(propertyName),
        requried, enableRtrim, 36, false,associationInfo, dbDataType, propertyName);
  }

  protected final DataTypePropertyInfo addAssoUdtPropertyInfo(String propertyName,
      String propertyDisplayKey, boolean required, boolean enableRtrim, int length,
      boolean isDefaultNull, SimpleAssoUdtPropertyInfo associationInfo, GspDbDataType dbDataType,
      String dbColumnName) {
      associationInfo.getMapping().put(getUdtResInfo(associationInfo.getUdtConfigId()).getEntityCode(),propertyName);
    return addPropertyInfo(propertyName, propertyDisplayKey, required, enableRtrim, length, 0,
        FieldType.Udt, ObjectType.UDT, null, isDefaultNull, false, dbDataType,
        dbColumnName, associationInfo);
  }

  protected final DataTypePropertyInfo addSimpleUdtPropertyInfo(String propertyName,boolean requried,boolean enableRtrim,String udtConfigId,GspDbDataType dbDataType)
  {
    return  addSimpleUdtPropertyInfo(propertyName,getFieldPropertyDisplayValue(propertyName),requried,enableRtrim,false,udtConfigId,dbDataType,propertyName);
  }

  private CefValueObjResInfo getUdtResInfo(String udtConfigID)
  {
    IUdtManager udtManager = (IUdtManager) UdtManagerUtils.getUdtFactory().createUdtManager(udtConfigID);

    CefValueObjModelResInfo valueObjModelResInfo = null;
    try {
      valueObjModelResInfo = (CefValueObjModelResInfo) udtManager.getClass()
          .getMethod("getUdtModelInfo").invoke(udtManager);
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    } catch (NoSuchMethodException e) {
      e.printStackTrace();
    }
    return (CefValueObjResInfo) valueObjModelResInfo
          .getCustomResource(valueObjModelResInfo.getRootNodeCode());
  }

  protected final DataTypePropertyInfo addSimpleUdtPropertyInfo(String propertyName,String propertyDisplayKey,boolean requried,boolean enableRtrim,boolean isMulti,String udtConfigId,GspDbDataType dbDataType,String dbColumnName)
  {
    IUdtManager udtManager = (IUdtManager) UdtManagerUtils.getUdtFactory().createUdtManager(udtConfigId);
    try {
      CefValueObjModelResInfo valueObjModelResInfo = (CefValueObjModelResInfo) udtManager.getClass()
          .getMethod("getUdtModelInfo").invoke(udtManager);
      CefValueObjResInfo valueObjResInfo = (CefValueObjResInfo) valueObjModelResInfo
          .getCustomResource(valueObjModelResInfo.getRootNodeCode());
      DataTypePropertyInfo udtPropInfo = valueObjResInfo.getEntityTypeInfo()
          .getPropertyInfo(valueObjResInfo.getEntityCode());
      if (udtPropInfo.getObjectInfo() instanceof EnumPropertyInfo)
      {
        SimpleEnumUdtPropertyInfo simpleEnumUdtPropertyInfo=new SimpleEnumUdtPropertyInfo(udtConfigId,false);
        EnumPropertyInfo enumPropertyInfo=new EnumPropertyInfo(((EnumPropertyInfo)udtPropInfo.getObjectInfo()).getRepoType());
        for(EnumValueInfo enumValueInfo:((EnumPropertyInfo)udtPropInfo.getObjectInfo()).getEnumValueInfos())
        {
          enumPropertyInfo.addEnumValueInfo(propertyDisplayKey.substring(0,propertyDisplayKey.lastIndexOf(".")),enumValueInfo.getEnumCode(),enumValueInfo.getDefaultName(),enumValueInfo.getStringIndex(),enumValueInfo.getIndex());
        }
        simpleEnumUdtPropertyInfo.setEnumInfo(enumPropertyInfo);
        return addPropertyInfo(propertyName, propertyDisplayKey, requried, enableRtrim,
            udtPropInfo.getLength(), udtPropInfo.getPrecision(), FieldType.Udt, ObjectType.UDT,
            null, false, isMulti, dbDataType, dbColumnName, simpleEnumUdtPropertyInfo);
      }
      else {
        SimpleUdtPropertyInfo simpleUdtPropertyInfo = new SimpleUdtPropertyInfo(udtConfigId, false,udtPropInfo.getFieldType());
        return addPropertyInfo(propertyName, propertyDisplayKey, requried, enableRtrim,
            udtPropInfo.getLength(), udtPropInfo.getPrecision(), FieldType.Udt, ObjectType.UDT,
            null, false, isMulti, dbDataType, dbColumnName, simpleUdtPropertyInfo);
      }
    } catch (IllegalAccessException var10) {
      throw new RuntimeException(var10);
    } catch (InvocationTargetException var11) {
      throw new RuntimeException(var11);
    } catch (NoSuchMethodException var12) {
      throw new RuntimeException(var12);
    }
  }

  protected  final DataTypePropertyInfo addComplexUdtPropertyInfo(String propertyName,
      ComplexUdtPropertyInfo udtPropertyInfo)
  {
    return addComplexUdtPropertyInfo(propertyName,getFieldPropertyDisplayValue(propertyName),udtPropertyInfo);
  }

  protected  final DataTypePropertyInfo addComplexUdtPropertyInfo(String propertyName,String propertyDisplayValueKey,
      ComplexUdtPropertyInfo udtPropertyInfo)
  {
    return addPropertyInfo(propertyName, propertyDisplayValueKey, false, false, 0, 0,
        FieldType.Udt, ObjectType.UDT, null, false, false, null,
        "", udtPropertyInfo);
  }

  protected  final DataTypePropertyInfo addComplexUdtPropertyInfo(String propertyName,
      ComplexUdtPropertyInfo udtPropertyInfo,GspDbDataType dbDataType)
  {
    return addComplexUdtPropertyInfo(propertyName,getFieldPropertyDisplayValue(propertyName),udtPropertyInfo,dbDataType,propertyName);
  }

  protected  final DataTypePropertyInfo addComplexUdtPropertyInfo(String propertyName,String propertyDisplayValueKey,
      ComplexUdtPropertyInfo udtPropertyInfo,GspDbDataType dbDataType,String dbColumnName)
  {
    for(Map.Entry<String, DataTypePropertyInfo> refColumn:udtPropertyInfo.getPropertyInfos().entrySet())
    {
      refColumn.getValue().setDbColumnName(dbColumnName);
      refColumn.getValue().setDbDataType(dbDataType);
    }
    return addPropertyInfo(propertyName, propertyDisplayValueKey, false, false, 0, 0,
        FieldType.Udt, ObjectType.UDT, null, false, false, dbDataType,
        dbColumnName, udtPropertyInfo);
  }



  protected DataTypePropertyInfo createDataTypePropertyInfo(String propertyName,
      String displayValueKey, boolean required, boolean enableRtrim, int length,
      int precision, FieldType fieldType, ObjectType objectType, PropertyDefaultValue defaultValue,
      boolean isMulti, boolean defaultNull,GspDbDataType dbDataType,String dbColumnName,
      BasePropertyInfo basePropertyInfo) {
    BefPropertyInfo befPropertyInfo=new BefPropertyInfo(propertyName,displayValueKey,required,enableRtrim,length,precision,fieldType,objectType,basePropertyInfo,defaultValue,isMulti,defaultNull);
    befPropertyInfo.setDbDataType(dbDataType);
    befPropertyInfo.setDbColumnName(dbColumnName);
    return befPropertyInfo;
  }

  private ColumnGenerateInfo columnGenerateInfo;

  public void setColumnGenerateInfo(ColumnGenerateInfo columnGenerateInfo) {
    this.columnGenerateInfo = columnGenerateInfo;
  }
  public ColumnGenerateInfo getColumnGenerateInfo(){
      return this.columnGenerateInfo;
  }
}
